/*
 * Copyright (c) 2024 Huawei Technologies Co.,Ltd.
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 * http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * ---------------------------------------------------------------------------------------
 *
 * imcs_alloc.h
 *
 *
 *
 * IDENTIFICATION
 * src/include/access/imcs/imcs_allocspace.h
 *
 * ---------------------------------------------------------------------------------------
 */

#ifndef IMCS_ALLOC_H
#define IMCS_ALLOC_H

#include "postgres.h"
#include "knl/knl_variable.h"
#include "storage/smgr/relfilenode.h"
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "imcs.h"

typedef struct {
    uint64 beginOffset;
    uint64 size;
} IMCSFreeSpaceDesc;

typedef CFileNode IMCSColumnFileTag;
typedef IMCSFreeSpaceDesc IMCSSpaceDesc;

#define DEFAULT_NUM_OF_FREE_SPACE_IM_SLOTS 2000
#define INVALID_IMCS_FREE_SPACE 0xffffffffffffffff
#define InvalidIMCStoreOffset INVALID_IMCS_FREE_SPACE
#define MinAvailableIMCStoreFSMSize 1024

/* Defines max number of holds in column.
 * If there are too many holds, we should exec vacuum and do not use the free space.
 */
#define MaxNumOfIMHoleFSM (100 * 1024 * 1024 / 16)

#define IsValidImcsFreeSpaceDesc(desc) ((desc)->size != INVALID_IMCS_FREE_SPACE)

extern Size ImcsAllocatorShmSize();

class IMCSFreeSpace : public BaseObject {
public:
    IMCSFreeSpace(int maxSize)
    {
        Initialize(maxSize);
    };
    IMCSFreeSpace()
    {
        Initialize(DEFAULT_NUM_OF_FREE_SPACE_IM_SLOTS);
    };
    virtual ~IMCSFreeSpace();
    virtual void Destroy();

    void Push(_in_ const IMCSFreeSpaceDesc &desc);

    void PopDescWithMaxSize(_out_ IMCSFreeSpaceDesc &desc);

    void GetDescWithMaxSize(_out_ IMCSFreeSpaceDesc &desc);

    bool IsEmpty()
    {
        return m_descNum == 0;
    }

    bool IsFull()
    {
        return m_descNum == m_maxSize;
    }

    bool HasEnoughSpace(Size size);

public: /* STATIC METHODS */
    static void ComputeFreeSpace(_in_ AttrNumber attno, _in_ Relation cudescIndexRel, _in_ Relation cudescHeapRel,
        __inout IMCSFreeSpace *fspace);

private:
    void Initialize(int maxSize);

    IMCSFreeSpaceDesc *m_descs;
    int m_descNum;
    int m_maxSize;
};

class IMCSAllocator : public BaseObject {
private:
    IMCSAllocator();
    virtual ~IMCSAllocator();

public:
    static void InitColSpaceCache(void);
    static void ResetColSpaceCache(void);

    static uint32 GetNextCUID(Relation rel);

    /* Now we need lock the relation before acquire space. */
    static void LockRelForAcquireSpace(Relation rel);

    static void ReleaseRelForAcquireSpace(Relation rel);

    static uint32 AcquireFileSpace(const CFileNode &cnode, uint64 extend_offset, uint64 cu_offset, uint32 cu_size);
    /* Acquire space for IMCU */
    static uint64 AcquireSpace(const CFileNode &cnode, Size size, int align_size);

    /* Acquire space for IMCU from free space */
    static uint64 TryAcquireSpaceFromFSM(IMCSFreeSpace *fsm, Size size, int align_size);

    /* Invalid column cache */
    static void InvalidColSpaceCache(const CFileNode &cnode);

    static bool ColSpaceCacheExist(const CFileNode *cnodes, int n_column);

    static uint64 GetExtendOffset(uint64 max_offset);
    static uint32 CalcExtendSize(uint64 cu_offset, uint32 cu_size, uint64 extend_offset);
};

#endif
